昨天我們已經將登入與註冊頁面寫完拉,今天我們將要來實際的串接功能。我們會使用 Firebase 這個由 Google 所提供的強大服務來進行實作。
Firebase 是 2011 年創立,並於 2014 年由 Google 收購的熱門應用程式後端服務平台。它提供了一系列的工具與服務,包括了Firestore、Firebase Auth、監控分析、資料庫、通知與 ML Kit 等等。
我們在此次專案中實作登入的功能,便是需要透過 Firebase Auth 的助力來完成。因此我們需要進行幾個設定。
官網:https://firebase.google.com/
您可以直接透過 Google 帳戶進行登入,一但登入之後便會看到以下畫面
點選「建立專案」來開始專案的設定。接下來為您的專案取名,並點選下一步到底即可建立專案。這邊我將我的專案取名做 micro-news-app
,等待建立好後即可從主控台中進入專案頁面,畫面如下。
請點選「Authentication」的頁面中的「開始使用」,便會進入請你新增第一種登入方式。
請選擇「電子郵件/密碼」,開啟開關後儲存,您就已經完成 Firebase Auth 的設定囉。
Firebase CLI (command line interface)是 Firebase 提供的命令列介面,透過指令來進行 firebase 的操作。
由於前一章節有帶大家安裝 nodejs
,因此我們可以很方面的透過 npm
來將套件全域安裝至電腦中,請打開終端機並輸入以下指令
# -g 表示 global,安裝的目標從原先的當前目錄底下改為至整台裝置
npm install -g firebase-tools
# 待安裝完畢後進行登入
firebase login
# 列出該帳號底下的專案列表
firebase projects:list
此時您應該可以在顯示的專案列表中看到方才透過網頁在 firebase 所建立 news app 專案。
請先開啟上一章節所建立的 News App 專案資料夾,並開啟終端機。
FlutterFire CLI 是 Firebase 官方提供給 Flutter 開發使用的插件工具
# 下載 flutterfire cli
dart pub global activate flutterfire_cli
# 針對 app 進行配置
flutterfire configure
你會看到 flutterfire 去偵測並要你選擇專案的支援平台,可自行選擇。(使用上下鍵移動游標,空白鍵進行選擇/刪除),完成後按下 Enter 便會開始幫你產生這些平台的配置檔,最後會問你是否正確並選擇 Yes 就大功告成拉。
完成後 Firebase 會自動在你的 Flutter 專案的 lib
資料夾底下產生 firebase_options.dart
的檔案,裡面會紀錄你的 APP 對應至這些平台的各種資訊。
完成上述的操作後,您還需要將 firebase 提供的數個套件載入至我們的專案中。打開終端機並輸入以下指令
# flutter 下載第三方套件的方式
# flutter pub add [名稱]
# 下載 firebase_core
flutter pub add firebase_core
# 下載 firebase_auth
flutter pub add firebase_auth
此時就會開始將 firebase_auth
與 firebase_core
以及其相依的套件一併的下載至你的 Flutter 專案中。你可以打開專案目錄底下的 pubspec.yml
其中的 dependencies
便會記錄該專案使用了哪些套件。(版本號碼跟我的不一樣沒關係,預設會下載最新版本)
# --------- 以上省略 ---------
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
firebase_core: ^2.16.0
firebase_auth: ^4.10.0
# --------- 以下省略 ---------
如此便完成了所有 firebase auth 的設定。
請打開 main.dart
並且再次把所有的內容皆移除並替換成以下程式碼。
import 'package:flutter/cupertino.dart';
void main() {
// 確保 widgets 環境已經初始化
WidgetsFlutterBinding.ensureInitialized();
// 根據當前平台的配置初始化 firebase
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return const CupertinoApp(
debugShowCheckedModeBanner: false, home: LoginScreen());
}
}
這裡介紹一個 VS Code 插件支援自動修正的功能,有時當我們使用了未引用的套件或變數時,使用此功能便可以自動幫我們從此專案中找到正確的內容進行引用。
如果你開發的是 iOS 應用程式,可能會遇到這個錯誤,以下提供解決方法:
ios
資料夾中,如果有 Podfile.lock
檔案請刪除pod repo remove trunk
sudo arch -x86_64 gem install ffi
arch -x86_64 pod install --repo-update
flutter run
希望你的專案可以因此執行起來QQ 當初看到這個錯誤我也是傻眼... 怎麼會預設幾乎啥都沒動過的竟然不能跑~
首先請先至 firebase console 的 Authentication 地方,在 Users 頁面點選「添加用戶」。我們至少需要一個使用者資訊才有辦法運用這組帳號密碼進行登入。
完成後,就可以回到程式碼中,並請開啟 login_screen.dart
檔案。由於登入的動作,是透過點擊登入按鈕才會觸發的,因此我們將實作寫在「登入」這個 CupertinoButton
的 onPressed
參數中。
Firebase 有提供一個函式名叫 signInWithEmailAndPassword
並夾帶信箱、密碼便可以進行驗證,我們將使用此函式來實作。
onPressed: () async {
try {
UserCredential user = await FirebaseAuth.instance
.signInWithEmailAndPassword(
// 夾帶 email 文字框輸入文字
email: _emailController.text,
// 夾帶 password 文字框輸入文字
password: _passwordController.text);
print(user);
} on FirebaseAuthException catch (e) {
print(e.code);
}
}
請將上面程式碼加至程式碼當中,並分別測試輸入正確資訊、輸入錯誤信箱格式、輸入錯誤信箱或密碼,各自得到的結果。
如果是正確的帳號資訊,我們就能成功經過驗證。若輸入的資訊錯誤,我們應該要給予相應的錯誤提示。
CupertinoAlertDialog
Alert dialog 通常使用於通知使用者某些需要確認的情況,例如當使用者輸入錯誤的帳號資訊時,我們便可以跳出通知告訴使用者「密碼錯誤」等等之類的訊息。
在 Cupertino 中定義了 CupertinoAlertDialog
讓我們完成這樣的行為,以下為使用範例
void _showAlertDialog(BuildContext context, String title, String message) {
showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
// 欲顯示的標題
title: Text(title),
// 欲顯示的訊息
content: Text(message),
actions: <CupertinoDialogAction>[
CupertinoDialogAction(
isDefaultAction: true,
onPressed: () {
// 關閉此通知
Navigator.pop(context);
},
child: const Text('關閉'),
),
],
),
);
}
我們額外傳入了 title
與 message
來讓通知可以提供更明確的訊息。
因此我們可以將 onPressed
改寫成以下樣式
onPressed: () async {
try {
UserCredential user = await FirebaseAuth.instance
.signInWithEmailAndPassword(
// 夾帶 email 文字框輸入文字
email: _emailController.text,
// 夾帶 password 文字框輸入文字
password: _passwordController.text);
print('登入成功');
} on FirebaseAuthException catch (e) {
if (e.code == 'invalid-email') {
_showAlertDialog(context, '登入失敗', '電子郵件格式錯誤');
} else if (e.code == 'INVALID_LOGIN_CREDENTIALS') {
_showAlertDialog(context, '登入失敗', '帳號或密碼錯誤');
} else {
_showAlertDialog(context, '登入失敗', '發生錯誤');
}
}
},
如此一來,一旦有錯誤便可以彈出錯誤訊息,與通知使用者當前狀態拉。
Navigator
昨天我們的程式碼告訴各位透過抽換 CupertinoApp
的 home
參數來達到獨立的頁面開發,但是其實實際流程應為若使用者未有帳號時,會點選登入頁面中的「註冊帳號」按鈕,頁面便會導向註冊頁面。
我們會透過 Navigator
來完成,在應用程式中每個頁面都是一個 Route
,而在頁面之中進行切換就是透過 Navigator
來完成。我們可以用一個 stack
來進行示意路由的狀態。
舉我們當前的應用程式為例:
route
,初始為「登入頁面」。push
的動作將「註冊頁面」堆疊置原先的頁面之上,並且保持永遠顯示最上層的原則。pop
stack 將最上層的 route
移除,回到原先的登入頁面。現在我們可以來實作拉,因為事件觸發是點擊按鈕之後,所以請找到 login_screen.dart
註冊帳號按鈕的 onPressed
參數,並參考以下程式碼:
onPressed: () {
// 以 CupertinoPageRoute 是表示以 Cupertino 的風格進行頁面跳轉
// push 註冊頁面
Navigator.push(context, CupertinoPageRoute(
builder: (context) {
return const RegisterScreen();
},
));
},
此外也打開 register_screen.dart
的「前往登入」按鈕 onPressed
參數,並參考以下程式碼:
onPressed: () {
Navigator.pop(context);
},
如此便可以成功的在兩頁面中進行切換拉!!有沒有越來越有樣子了呢
登入功能串的差不多拉~接下來我們要來把註冊的功能也一起完成,請開啟 register_screen.dart
檔案。
Firebase 有提供一個函式名叫 createUserWithEmailAndPassword
並夾帶信箱、密碼便可以進行註冊,我們將使用此函式來實作。
onPressed: () async {
try {
UserCredential newUser = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
print(newUser);
} on FirebaseAuthException catch (e) {
print(e.code);
}
},
請將上面程式碼加至程式碼當中,並同樣的分別測試輸入新使用者資訊、已存在使用者資訊、註冊一個使用者並將密碼設為 12345、錯誤信箱格式的結果
同樣的,如果是正確的帳號資訊,我們就能成功經過驗證。若輸入的資訊錯誤,我們應該要給予相應的錯誤提示。此時我們可以將上面介紹的 _showAlertDialog
複製至此檔案,同樣也用於顯示資訊給使用者。
在註冊的頁面上多了一個輸入框用於二次驗證輸入的密碼內容,按照註冊流程應該要先檢查是否「密碼」與「驗證密碼」的輸入內容是否相同,相同才讓 firebase 去進行註冊;否則跳出「輸入密碼不符」的錯誤訊息,因此同樣我們可以將上述程式碼進行改寫。
onPressed: () async {
if (_passwordController.text != _confirmPasswordController.text) {
_showAlertDialog(context, '密碼不一致', '請檢查您的密碼與驗證密碼欄位內容是否正確');
return;
}
try {
UserCredential newUser = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
print(newUser);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
_showAlertDialog(context, '密碼強度不足', '為了您帳號的安全性,請使用強度較高的密碼');
} else if (e.code == 'email-already-in-use') {
_showAlertDialog(context, '信箱已被註冊', '該信箱已被註冊,您可以使用該信箱登入或使用其他信箱進行註冊');
} else if (e.code == 'invalid-email') {
_showAlertDialog(context, '信箱格式錯誤', '請檢查您的信箱格式是否正確');
} else {
_showAlertDialog(context, '註冊失敗', '請稍後再試');
}
}
},
這麼一來,註冊的流程也算是正式完成拉。請試著註冊一組帳號,成功後便可以至 firebase console 上檢視 users 是否有方才建立的帳號資訊。
今天我們介紹:
經過今天的介紹,讓我們的應用程式已經有了基礎的帳號註冊與登入功能。不過這部分還沒完全結束!因為普遍的應用程式都有支援第三方登入,我們不能捨棄這個超級方便的功能呀~
因此明天的內容會延續今天的進度,串接 Google 登入以及實作忘記密碼的頁面喔!各位我們明天繼續囉~
今天的參考程式碼:https://github.com/ChungHanLin/micro_news_tutorial/tree/day12/micro_news_app